#!/usr/bin/perl
# 2014/05/12 randomize association map file

use strict;
use warnings;
use IO::File;
use Getopt::Std;
use Carp qw(croak);
$| = 0;

if(@ARGV != 4 or $ARGV[0] eq '--help'){
	die "Usage : $0 -i [original map file] -o [randomized map file]\n";
}

my %opt;
getopts("i:o:", \%opt);
my $FILE_map = $opt{i};
my $FILE_out = $opt{o};

use threads;
use Thread::Queue;
use Thread::Semaphore;

### ramdomize utility
use List::Util;

my $LINE_PER_PROCESS = 10000;
my $THREAD_NUMBER = 20;
my $semaphore = Thread::Semaphore->new($THREAD_NUMBER);
my $leftQues = Thread::Queue->new();
my $rightQues = Thread::Queue->new();

#---------------------------------------
# collect data
#---------------------------------------
my @tmpRight;
my $count = 0;
my $fh_map = IO::File->new($FILE_map) or die "cannot open $FILE_map: $!";
my $fh_out = IO::File->new($FILE_out, 'w') or die "cannot write $FILE_out: $!";
my $merge_thread = new threads(\&combine_and_output);
while($_ = $fh_map->getline()){
	s/\r?\n//;
	my ($id, $chr1, $loc1, $direction1, $mapQ1, $peakName1, $peakLoc1, $chr2, $loc2, $direction2, $mapQ2, $peakName2, $peakLoc2, $type, $num, $locations) = split /\t/;

	$leftQues->enqueue([$id, $chr1, $loc1, $direction1, $mapQ1, $peakName1, $peakLoc1]);
	push @tmpRight, [$chr2, $loc2, $direction2, $mapQ2, $peakName2, $peakLoc2];
	$count++;

	if($count > $LINE_PER_PROCESS){
		$semaphore->down();
		my $thread = new threads(\&randomlize_array, @tmpRight);
		@tmpRight = ();
		$count = 0;
	}
}
$fh_map->close();

# remaining
if($count > 0){
	$semaphore->down();
	my $thread = new threads(\&randomlize_array, @tmpRight);
}

# ループ脱出用
$leftQues->enqueue(undef);


### threadをすべて終わらせる
foreach my $th(threads->list()){
	$th->join();
}

$fh_out->close();

#---------------------------------------
# randomize data
#---------------------------------------
sub randomlize_array{
	my @data = @_;
	my @random = List::Util::shuffle @data;
	$rightQues->enqueue(@random);
	threads->yield();
	$semaphore->up();
}

#---------------------------------------
# combine data and output
#---------------------------------------
sub combine_and_output{
	while(my $L = $leftQues->dequeue()){
		my $R = $rightQues->dequeue();
		$fh_out->print(join("\t", @$L, @$R) . "\n");
		threads->yield();
	}
}



